Skip to content

[实例] 小球滚动

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>小球滚动</title>
    <!-- React 核心库,与宿主环境无关 -->
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <!-- 依赖核心库,将核心功能与页面结合 -->
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <!-- babel -->
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
    <style>
      .ball {
        background-color: red;
        border-radius: 50%;
        box-shadow: 0 0 25px 10px rgba(215, 215, 215, 0.5) inset;
        height: 100px;
        position: absolute;
        width: 100px;
      }
      .ball::before {
        background-color: #fff;
        border-radius: 50%;
        content: "";
        display: block;
        height: 12%;
        left: 20%;
        opacity: 0.3;
        position: absolute;
        top: 20%;
        transform: rotate(30deg);
        width: 8%;
      }
      .ball::after {
        background-color: #fff;
        border-radius: 50%;
        content: "";
        display: block;
        height: 7%;
        left: 32%;
        opacity: 0.3;
        position: absolute;
        top: 12%;
        transform: rotate(60deg);
        width: 5%;
      }

      body {
        background-color: #ffffff;
      }
    </style>
  </head>
  <body>
    <div id="root"></div>
    <script>
      /**
       * 获取随机数
       * @param {number} min
       * @param {number} max
       * @returns {number}
       */
      function getRandom(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
      }
    </script>
    <!-- 小球组件 -->
    <script type="text/babel">
      class Ball extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
            width: props.width || 100,
            height: props.width || 100,
            left: props.left || 0,
            top: props.top || 0,
            speedX: props.speedX || 200,
            speedY: props.speedY || 200,
            color: props.color || "red",
            opacity: props.opacity || 0.9,
          };
          const duration = 10;
          //
          setInterval(() => {
            let xDis = (this.state.speedX * duration) / 1000;
            let yDis = (this.state.speedY * duration) / 1000;
            let newLeft = this.state.left + xDis;
            let newTop = this.state.top + yDis;
            // 限制小球的左右移动范围
            if (newLeft <= 0) {
              newLeft = 0;
              this.setState({
                speedX: -this.state.speedX,
              });
            } else if (
              newLeft >=
              document.documentElement.clientWidth - this.state.width
            ) {
              newLeft = document.documentElement.clientWidth - this.state.width;
              this.setState({
                speedX: -this.state.speedX,
              });
            }
            // 限制小球的上下移动范围
            if (newTop <= 0) {
              newTop = 0;
              this.setState({
                speedY: -this.state.speedY,
              });
            } else if (
              newTop >=
              document.documentElement.clientHeight - this.state.width
            ) {
              newTop = document.documentElement.clientHeight - this.state.width;
              this.setState({
                speedY: -this.state.speedY,
              });
            }

            this.setState({
              left: newLeft,
              top: newTop,
            });
          }, duration);
        }
        render() {
          return (
            <>
              <div
                className="ball"
                style={{
                  width: this.state.width,
                  height: this.state.height,
                  left: this.state.left,
                  top: this.state.top,
                  background: this.state.color,
                  opacity: this.state.opacity,
                }}
              ></div>
            </>
          );
        }
      }
    </script>
    <!-- 小球列表组件 -->
    <script type="text/babel">
      class BallList extends React.Component {
        constructor(props) {
          super(props);
          let timer = null;
          this.state = {
            list: [],
          };
          timer = setInterval(() => {
            let list = this.state.list;
            list.push({
              left: getRandom(0, document.documentElement.clientWidth - 100),
              top: getRandom(0, document.documentElement.clientHeight - 100),
              width: getRandom(50, 200),
              height: getRandom(50, 200),
              speedX: getRandom(100, 300),
              speedY: getRandom(100, 300),
              opacity: getRandom(10, 90) / 100,
              color: `rgb(${getRandom(0, 255)},${getRandom(0, 255)},${getRandom(
                0,
                255
              )})`,
            });
            this.setState({
              list: list,
            });
            if (this.state.list.length > 30) {
              clearInterval(timer);
            }
          }, 1000);
        }
        render() {
          return (
            <>
              {this.state.list.map((item, index) => (
                <Ball key={index} {...item} />
              ))}
            </>
          );
        }
      }
    </script>
    <script type="text/babel">
      ReactDOM.render(<BallList />, document.getElementById("root"));
    </script>
  </body>
</html>

Released under the MIT License.